package cn.backpackerxl.easyJDBC.main;

import java.lang.reflect.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class EasyJDBCRepository implements InvocationHandler {
    private final Object obj;
    private final Class<?> clazzI;

    public EasyJDBCRepository(Class<?> clazzI) {
        this.obj = new EasyJDBCExecutor<>();
        this.clazzI = clazzI;
        String pack = Thread.currentThread().getStackTrace()[2].getClassName();
        initValue(clazzI, pack);
    }

    /**
     * init value
     *
     * @param clazzI
     */
    private void initValue(Class<?> clazzI, String pack) {
        try {
            ParameterizedType parameterizedType = (ParameterizedType) clazzI.getGenericInterfaces()[0];
            Type[] ty = parameterizedType.getActualTypeArguments();
            List<String> list = Arrays.stream(ty).map(Type::getTypeName).collect(Collectors.toList());
            List<Method> methods = Arrays.stream(EasyJDBCExecutor.class.getDeclaredMethods()).filter(method -> !method.isAccessible()).collect(Collectors.toList());
            for (Method me : methods) {
                me.setAccessible(true);
                if (me.getName().equals("setMethods")) {
                    me.invoke(this.obj, (Object) Class.forName(pack).getDeclaredMethods());
                }
                if (me.getName().equals("setClazz") && list.size() == me.getParameterCount()) {
                    me.invoke(this.obj, list.toArray());
                }
            }
        } catch (InvocationTargetException | IllegalAccessException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    public EasyJDBCRepository(Class<?> clazzI, Object obj) {
        this.obj = obj;
        this.clazzI = clazzI;
        String pack = Thread.currentThread().getStackTrace()[2].getClassName();
        initValue(clazzI, pack);
    }

    public Object init() {
        return Proxy.newProxyInstance(this.obj.getClass().getClassLoader(), new Class[]{EasyJDBCRef.class, this.clazzI}, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(this.obj, args);
    }
}
